package util

import (
	"errors"
	logger "gitee.com/zaper/private-logger"
	"gitee.com/zaper/software-framework/cert_mgr"
	"io"
	"net"
	"net/http"
	"sync"
	"time"
)

var (
	httpClientManagerSingle *HttpClientManager
	sw                      sync.Mutex
)

type HttpClientManager struct {
	Httpclient *http.Client
}

func NewHttpClientManager() *HttpClientManager {
	sw.Lock()
	defer sw.Unlock()
	if httpClientManagerSingle != nil {
		return httpClientManagerSingle
	}
	httpclient := &http.Client{
		Timeout: 30 * time.Second, // 请求超时时间
		Transport: &http.Transport{
			MaxIdleConns:        100,              // 最大空闲连接数
			IdleConnTimeout:     90 * time.Second, // 空闲连接超时
			TLSHandshakeTimeout: 10 * time.Second, // TLS握手超时
			DialContext: (&net.Dialer{
				Timeout:   30 * time.Second, // 连接超时
				KeepAlive: 30 * time.Second, // 保持活动连接时间
			}).DialContext,
			TLSClientConfig: cert_mgr.GetClientTlsConfig(),
		},
	}
	httpClientManagerSingle = &HttpClientManager{
		Httpclient: httpclient,
	}
	return httpClientManagerSingle
}

func (httpClientManager *HttpClientManager) Get(url string) ([]byte, error) {
	resp, err := httpClientManager.Httpclient.Get(url)
	if err != nil {
		return nil, errors.New("get request fail")
	}
	result, err := parseHttpResult(resp)
	if err != nil {
		return nil, errors.New("parse get httpResult fail")
	}
	return result, nil
}

func (httpClientManager *HttpClientManager) Post(url, contentType string, body io.Reader) ([]byte, error) {
	resp, err := httpClientManager.Httpclient.Post(url, contentType, body)
	if err != nil {
		return nil, errors.New("post request fail")
	}
	result, err := parseHttpResult(resp)
	if err != nil {
		return nil, errors.New("parse post httpResult fail")
	}
	return result, nil
}

func parseHttpResult(resp *http.Response) ([]byte, error) {
	defer func() {
		if resp == nil || resp.Body == nil {
			err := resp.Body.Close()
			if err != nil {
				logger.Warnf("close response fail, err is %v", err)
			}
		}
	}()
	if resp == nil || resp.Body == nil {
		return nil, errors.New("response request err")
	}
	if resp.StatusCode != 200 {
		return nil, errors.New("http status is not 200")
	}
	r, err := io.ReadAll(resp.Body)
	if err != nil {
		return nil, errors.New("read resp body fail")
	}
	return r, nil
}
